#pragma once

#include <string>

#include "noncopyable.h"

// LOG_INFO("%s %d", arg1, arg2)
/*
 * 1.定义了宏 LOG_INFO，接受一个字符串 logmsgFormat 作为日志消息的格式，以及一个可变参数列表 ...(使用 __VA_ARGS__ 表示)。
 *   这允许用户自定义日志消息的格式，并插入多个变量参数。
 * 2.do{...}while(0)用于创建一个只执行一次的循环。这个结构通常在宏定义中使用，以保证宏定义中的多个语句可以作为一个单独的块执行，
 *   避免因宏展开而引起的语法错误。
 * 3.Logger::instance() 方法获取了日志系统的一个引用，通常这种设计模式称为单例模式，确保全局只有一个日志系统实例。
 * 4.使用 snprintf 函数将格式化的日志消息写入到一个字符数组 buf 中。buf 的大小限制为 1024 字符。
 *   logmsgFormat 和 __VA_ARGS__ 允许函数按照指定的格式输出变化的数据。
 */
#define LOG_INFO(logmsgFormat, ...) \
    do \
    { \
        Logger& logger = Logger::instance(); \
        logger.setLogLevel(INFO); \
        char buf[1024] = {0}; \
        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \
        logger.log(buf); \
    } while(0)

#define LOG_ERROR(logmsgFormat, ...) \
    do \
    { \
        Logger& logger = Logger::instance(); \
        logger.setLogLevel(ERROR); \
        char buf[1024] = {0}; \
        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \
        logger.log(buf); \
    } while(0)

#define LOG_FATAL(logmsgFormat, ...) \
    do \
    { \
        Logger& logger = Logger::instance(); \
        logger.setLogLevel(FATAL); \
        char buf[1024] = {0}; \
        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \
        logger.log(buf); \
        exit(-1); \
    } while(0)

// 因为DEBUG调试信息比较多，不能一直输出，占用资源。
// 这种方法在软件开发中常用于确保开发和生产环境之间的代码可以灵活切换，同时保持生产环境的代码清洁和高效。
#ifdef MUDEBUG
#define LOG_DEBUG(logmsgFormat, ...) \
    do \
    { \
        Logger& logger = Logger::instance(); \
        logger.setLogLevel(DEBUG); \
        char buf[1024] = {0}; \
        snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \
        logger.log(buf); \
    } while(0)
#else
    #define LOG_DEBUG(logmsgFormat, ...)
#endif

// 定义日志的级别 INFO ERROR FATAL DEBUG
enum LogLevel
{
    INFO,   // 普通信息
    ERROR,  // 错误信息
    FATAL,  // core信息
    DEBUG,  // 调试信息
};

// 输出一个日志类
class Logger : noncopyable
{
public:
    // 获取日志唯一的实例对象
    static Logger& instance();
    // 设置日志级别
    void setLogLevel(int level);
    // 写日志
    void log(std::string msg);

private:
    int logLevel_;
    Logger(){}
};














